﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.ComponentModel;
using System.Windows.Forms;

namespace LowLevelGraphics.Types.Interval
{
    /// <summary>
    /// The boundaries are momentarily included (>= ...)
    /// If they should be excluded use ONLY greater or smaller sign
    /// </summary>
    [DebuggerDisplay("[{m_fMin}, {m_fMax}]")]
    [TypeConverter(typeof(IntervalConverter<float, FloatInterval>))]
    public class FloatInterval : IComparable<FloatInterval>, ICloneable, ICustomTypeDescriptor
    {
        protected float m_fMin = 0;
        protected float m_fMax = 0;

        /// <summary>
        /// Default Constructor
        /// </summary>
        public FloatInterval()
        {
        }

        /// <summary>
        /// Specify min and max bound for interval
        /// </summary>
        /// <param name="_dMin"></param>
        /// <param name="_dMax"></param>
        public FloatInterval(float _dMin, float _dMax)
        {
            m_fMin = _dMin;
            m_fMax = _dMax;
        }

        /// <summary>
        /// Max value of this interval (upper boundary)
        /// </summary>
        public float Max
        {
            get { return m_fMax; }
            set { m_fMax = value; }
        }

        /// <summary>
        /// Min value of this interval (lower boundary)
        /// </summary>
        public float Min
        {
            get { return m_fMin; }
            set { m_fMin = value; }
        }

        /// <summary>
        /// Returns true, if the value is inside given interval
        /// </summary>
        /// <param name="_dValue"></param>
        /// <returns></returns>
        public bool Contains(float _dValue)
        {
            return _dValue >= m_fMin && _dValue <= m_fMax;
        }

        /// <summary>
        /// Check if the current interval completely contains given interval
        /// </summary>
        /// <param name="_doubleInterval"></param>
        /// <returns></returns>
        public bool Contains(FloatInterval _doubleInterval)
        {
            return m_fMin<=_doubleInterval.m_fMin && m_fMax>= _doubleInterval.m_fMax;
        }

        /// <summary>
        /// This will check if an interval is overlapping, i.e. concrete:
        /// True if one of the given boundaries is contained inside the interval.
        /// The other boundary has to be outside the interval.
        /// </summary>
        /// <param name="_doubleInterval"></param>
        /// <returns></returns>
        public bool Intersects(FloatInterval _doubleInterval)
        {
            return 
                (Contains(_doubleInterval.m_fMax) && !Contains(_doubleInterval.m_fMin))
                || (Contains(_doubleInterval.m_fMin) && !Contains(_doubleInterval.m_fMax))
                ;
        }

        /// <summary>
        /// This returns the size of the interval.
        /// Also negative sizes are allowed to show the direction.
        /// Use Abs(Size) if direction is unimportant
        /// </summary>
        public double Size
        {
            get { return m_fMax - m_fMin; }
        }

        #region IComparable<FloatInterval> Members

        /// <summary>
        /// An interval is bigger if its size is bigger
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        public int CompareTo(FloatInterval other)
        {
            return this.Size.CompareTo(other.Size);
        }

        #endregion

        /// <summary>
        /// Get interval as string in notation e.g. [0,1]
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return string.Format("[{0},{1}]", m_fMin, m_fMax);
        }

        #region ICloneable Members

        /// <summary>
        /// Use this to clone the interval
        /// </summary>
        /// <returns></returns>
        public object Clone()
        {
            return new FloatInterval(this.m_fMin, this.m_fMax);
        }

        #endregion

        #region ICustomTypeDescriptor Members

        public AttributeCollection GetAttributes()
        {
            return null;
        }

        public string GetClassName()
        {
            return TypeDescriptor.GetClassName(this, true);
        }

        public string GetComponentName()
        {
            throw new NotImplementedException();
        }

        public TypeConverter GetConverter()
        {
            return null;
        }

        public EventDescriptor GetDefaultEvent()
        {
            return null;
        }

        public PropertyDescriptor GetDefaultProperty()
        {
            return null;
        }

        public object GetEditor(Type editorBaseType)
        {
            return typeof(NumericUpDown);
        }

        public EventDescriptorCollection GetEvents(Attribute[] attributes)
        {
            return TypeDescriptor.GetEvents(this, attributes);
        }

        public EventDescriptorCollection GetEvents()
        {
            return TypeDescriptor.GetEvents(this);
        }

        public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
        {
            return TypeDescriptor.GetProperties(this);
        }

        public PropertyDescriptorCollection GetProperties()
        {
            return null;
        }

        public object GetPropertyOwner(PropertyDescriptor pd)
        {
            return this;
        }

        #endregion
    }
}
